﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using MALRECrewrite.Etc;
using MALRECrewrite.Models;
using MartinsEssentials.MVVM;

namespace MALRECrewrite.ViewModels
{
    public class SequelsViewModel : ViewModelBase
    {
        public bool IsLoaded { get; set; }

        private List<SeasonAnime> _SequelRefs = new List<SeasonAnime>();

        public List<SeasonAnime> SequelRefs
        {
            get
            {
                return _SequelRefs;
            }
            set
            {
                if (value != _SequelRefs)
                {
                    _SequelRefs = value;
                    OnPropertyChanged("SequelRefs");
                }
            }
        }

        private ObservableCollection<SeasonAnime> _RootReferences;

        public ObservableCollection<SeasonAnime> RootReferences
        {
            get
            {
                return _RootReferences;
            }
            set
            {
                if (value != _RootReferences)
                {
                    _RootReferences = value;
                    OnPropertyChanged("RootReferences");
                }
            }
        }

        public async void CheckAnimeListForNewSeasons()
        {
            if (IsLoaded)
                return;

            //await TaskEx.Run((Action)delegate
            //{
            if (!await new DataSaver().LoadSequelsData(this))
            {
                foreach (Anime a in App.DataModel.Animes.Where(x => !x.IsDropped))
                {
                    if (SequelRefs.Count(h => h.Aid == a.Aid) == 0)
                        LoadData(a.Aid.ToString());
                }

                SequelRefs.ForEach(x => x.RemoveParents());
            }

            foreach (SeasonAnime s in SequelRefs)
            {
                Debug.WriteLine(s.Title);
            }
            //});

            var roots = SequelRefs.Where(x => x.IsRootAnime).ToList();
            roots.ForEach(x => x.RemoveRecursion(roots));

            RootReferences = new ObservableCollection<SeasonAnime>(SequelRefs.Where(x => x.IsRootAnime));

            IsLoaded = true;
        }

        private async Task Load()
        {
            if (IsLoaded)
                return;

            if (!await new DataSaver().LoadSequelsData(this))
            {
                IsLoaded = false;
            }
            else
            {
                var roots = SequelRefs.Where(x => x.IsRootAnime).ToList();
                roots.ForEach(x => x.RemoveRecursion(roots));

                RootReferences = new ObservableCollection<SeasonAnime>(SequelRefs.Where(x => x.IsRootAnime));

                IsLoaded = true;
            }
        }

        public SeasonAnime LoadData(string ure)
        {
            int aid = int.Parse(ure);

            if (SequelRefs.Count(gj => gj.Aid == aid) > 0)
            {
                Debug.WriteLine("Found: " + GetAnimeNameByAid(aid));
                return SequelRefs.Where(hn => hn.Aid == aid).First();
            }

            SeasonAnime sr = null;

            WebClient wc = new WebClient();
            Debug.WriteLine("LoadData: " + GetAnimeNameByAid(aid));
            wc.Encoding = Encoding.UTF8;
            string result = wc.DownloadString(new Uri("http://mal-api.com/anime/" + aid + "?format=xml"));
            XmlDocument x = new XmlDocument();
            x.LoadXml(result);

            bool isInList = App.DataModel.Animes != null && App.DataModel.Animes.Count(j => j.Aid == aid) > 0;
            sr = new SeasonAnime(int.Parse(x.SelectSingleNode("/anime/id").InnerText), WebUtility.HtmlDecode(x.SelectSingleNode("/anime/title").InnerText), isInList, "");

            SequelRefs.Add(sr);

            string[] nodes = new string[] { "prequel", "sequel", "side_story", "spin_off", "parent_story" };

            foreach (string node in nodes)
            {
                XmlNodeList xn = x.SelectNodes("/anime/" + node);

                foreach (XmlNode z in xn)
                {
                    Debug.WriteLine("Node: " + node + " Aid: " + GetAnimeNameByAid(int.Parse(z["anime_id"].InnerText)));
                    SeasonAnime t = LoadData(z["anime_id"].InnerText);
                    sr.AddToReferences(t, (MALRECrewrite.Models.Reference.ReferenceType)Enum.Parse(typeof(MALRECrewrite.Models.Reference.ReferenceType), node));
                }
            }

            return sr;
        }

        private string GetAnimeNameByAid(int aid)
        {
            if (App.DataModel.Animes != null)
            {
                return App.DataModel.Animes.Where(hk => hk.Aid == aid).Select(hn => hn.Title).FirstOrDefault() ?? aid.ToString();
            }
            return aid.ToString();
        }

        public async Task<List<int>> GetChildNodesOfAnime(Anime a)
        {
            List<int> childs = new List<int>();

            if (!IsLoaded)
            {
                await Load();
                if (!IsLoaded)
                    return childs;
            }

            var anime = RootReferences.Where(x=>x.Aid == a.Aid).FirstOrDefault();

            if (anime != null)
            {
                var t = anime.GetChildren(new List<SeasonAnime>());
                t.ForEach(x => childs.Add(x.Aid));
            }

            return childs.Distinct().ToList();
        }

        private class SequelReferenceComparer : IEqualityComparer<SeasonAnime>
        {
            public bool Equals(SeasonAnime x, SeasonAnime y)
            {
                return x.Aid == y.Aid;
            }

            public int GetHashCode(SeasonAnime obj)
            {
                return obj.Aid.GetHashCode();
            }
        }

        //    public void BuildTree()
        //    {
        //        Dictionary<int, List<SequelsRef>> sr = new Dictionary<int, List<SequelsRef>>();

        //        foreach (Anime a in App.DataModel.Animes)
        //        {
        //            foreach (SequelReference s in a.SideStory)
        //            {
        //                AddToDictionary(sr, s, a, MALRECrewrite.ViewModels.SequelsRef.AnimeType.SideStory);
        //            }

        //            foreach (SequelReference s in a.ParentStory)
        //            {
        //                AddToDictionary(sr, s, a, MALRECrewrite.ViewModels.SequelsRef.AnimeType.ParentStory);
        //            }

        //            foreach (SequelReference s in a.Prequel)
        //            {
        //                AddToDictionary(sr, s, a, MALRECrewrite.ViewModels.SequelsRef.AnimeType.Prequel);
        //            }

        //            foreach (SequelReference s in a.Sequel)
        //            {
        //                AddToDictionary(sr, s, a, MALRECrewrite.ViewModels.SequelsRef.AnimeType.Sequel);
        //            }

        //            foreach (SequelReference s in a.SpinOff)
        //            {
        //                AddToDictionary(sr, s, a, MALRECrewrite.ViewModels.SequelsRef.AnimeType.SpinOff);
        //            }
        //        }

        //        #region debug
        //        foreach (KeyValuePair<int, List<SequelsRef>> kvp in sr)
        //        {
        //            string complete = "Animeid: {0} \n";

        //            string sidestorys = "";
        //            foreach (SequelsRef s in kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.SideStory))
        //                sidestorys += String.Format("-> Title: {0}\n", s.Title);

        //            if (kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.SideStory).Count() > 0)
        //                complete += "Sidestorys: \n{1}";

        //            string parentStorys = "";
        //            foreach (SequelsRef s in kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.ParentStory))
        //                parentStorys += String.Format("-> Title: {0}\n", s.Title);

        //            if (kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.ParentStory).Count() > 0)
        //                complete += "ParentStory: \n{2}";

        //            string prequels = "";
        //            foreach (SequelsRef s in kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.Prequel))
        //                prequels += String.Format("-> Title: {0}\n", s.Title);

        //            if (kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.Prequel).Count() > 0)
        //                complete += "Prequel: \n{3}";

        //            string sequels = "";
        //            foreach (SequelsRef s in kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.Sequel))
        //                sequels += String.Format("-> Title: {0}\n", s.Title);

        //            if (kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.Sequel).Count() > 0)
        //                complete += "Sequel: \n{4}";

        //            string spinOffs = "";
        //            foreach (SequelsRef s in kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.SpinOff))
        //                spinOffs += String.Format("-> Title: {0}\n", s.Title);

        //            if (kvp.Value.Where(l => l.Type == SequelsRef.AnimeType.SpinOff).Count() > 0)
        //                complete += "SpinOff: \n{5}";

        //            Debug.WriteLine(String.Format(complete,
        //                App.DataModel.Animes.Where(x => x.Aid == kvp.Key).Select(z => z.Title).First(),
        //                sidestorys,
        //                parentStorys,
        //                prequels,
        //                sequels,
        //                spinOffs
        //                ));
        //        }
        //        #endregion

        //        Dictionary<int,AnimesWithReferences> ra = new Dictionary<int,AnimesWithReferences>();
        //        // Roots
        //        foreach (KeyValuePair<int, List<SequelsRef>> kvp in sr.Where(o => o.Value.Count(x => x.Type == SequelsRef.AnimeType.ParentStory) == 0 && o.Value.Count(x => x.Type == SequelsRef.AnimeType.Prequel) == 0))
        //        {
        //                AnimesWithReferences r = new AnimesWithReferences();
        //                r.Aid = kvp.Key;

        //                kvp.Value.ForEach(z => r.AddToList(z));
        //                ra.Add(r.Aid, r);
        //        }

        //        #region Debug
        //        Debug.WriteLine("----------------------------------------------");
        //        foreach (KeyValuePair<int, AnimesWithReferences> kvp in ra)
        //            Debug.WriteLine(String.Format("Roots: {0}", App.DataModel.Animes.Where(x => x.Aid == kvp.Key).Select(z => z.Title).First()));
        //        #endregion

        //        Dictionary<int, List<SequelsRef>> stillToAdd = sr.Where(o => o.Value.Count(x => x.Type == SequelsRef.AnimeType.ParentStory) != 0 || o.Value.Count(x => x.Type == SequelsRef.AnimeType.Prequel) != 0).ToDictionary(h=>h.Key, t=>t.Value);
        //        while (stillToAdd.Count > 0)
        //        {
        //            List<int> toRemove = new List<int>();
        //            foreach (KeyValuePair<int, List<SequelsRef>> kvp in stillToAdd)
        //            {
        //                foreach (KeyValuePair<int, AnimesWithReferences> u in ra)
        //                {
        //                    foreach (SequelsRef jn in kvp.Value)
        //                    {
        //                        u.Value.ContainsItem(jn);
        //                    }
        //                }
        //            }

        //            toRemove.ForEach(j => stillToAdd.Remove(j));
        //        }

        //    }

        //    private void AddToDictionary(Dictionary<int, List<SequelsRef>> sr, SequelReference s, Anime a, MALRECrewrite.ViewModels.SequelsRef.AnimeType t)
        //    {
        //        if (sr.ContainsKey(a.Aid))
        //        {
        //            if (sr[a.Aid].Count(h => h.Aid == s.Aid && h.Type == t) == 0)
        //                sr[a.Aid].Add(new SequelsRef() { Aid = s.Aid, IsInAnimelist = s.IsInAnimelist, Title = s.Title, Type = t });
        //        }
        //        else
        //        {
        //            List<SequelsRef> temp = new List<SequelsRef>();
        //            temp.Add(new SequelsRef() { Aid = s.Aid, IsInAnimelist = s.IsInAnimelist, Title = s.Title, Type = t });
        //            sr.Add(a.Aid, temp);
        //        }
        //    }
        //}

        //public class SequelsRef : SequelReference
        //{
        //    public enum AnimeType
        //    {
        //        Prequel = 0,
        //        Sequel,
        //        SideStory,
        //        SpinOff,
        //        ParentStory
        //    }

        //    public AnimeType Type { get; set; }
        //}

        //public class AnimesWithReferences : SequelReference
        //{
        //    public AnimesWithReferences(SequelReference s)
        //        : base(s.Aid, s.Title, s.IsInAnimelist)
        //    {
        //        Prequel = new List<AnimesWithReferences>();
        //        Sequel = new List<AnimesWithReferences>();
        //        SideStory = new List<AnimesWithReferences>();
        //        SpinOff = new List<AnimesWithReferences>();
        //        ParentStory = new List<AnimesWithReferences>();
        //    }

        //    public List<AnimesWithReferences> Prequel { get; set; }

        //    public List<AnimesWithReferences> Sequel { get; set; }

        //    public List<AnimesWithReferences> SideStory { get; set; }

        //    public List<AnimesWithReferences> SpinOff { get; set; }

        //    public List<AnimesWithReferences> ParentStory { get; set; }

        //    public AnimesWithReferences()
        //    {
        //        Prequel = new List<AnimesWithReferences>();
        //        Sequel = new List<AnimesWithReferences>();
        //        SideStory = new List<AnimesWithReferences>();
        //        SpinOff = new List<AnimesWithReferences>();
        //        ParentStory = new List<AnimesWithReferences>();
        //    }

        //    public void AddToList(SequelsRef sr)
        //    {
        //        switch (sr.Type)
        //        {
        //            case SequelsRef.AnimeType.Sequel:
        //                Sequel.Add(new AnimesWithReferences(sr));
        //                break;
        //            case SequelsRef.AnimeType.Prequel:
        //                Prequel.Add(new AnimesWithReferences(sr));
        //                break;

        //            case SequelsRef.AnimeType.SideStory:
        //                SideStory.Add(new AnimesWithReferences(sr));
        //                break;

        //            case SequelsRef.AnimeType.SpinOff:
        //                SpinOff.Add(new AnimesWithReferences(sr));
        //                break;

        //            case SequelsRef.AnimeType.ParentStory:
        //                ParentStory.Add(new AnimesWithReferences(sr));
        //                break;
        //        }
        //    }

        //    public bool ContainsItem(SequelsRef sr)
        //    {
        //        List<AnimesWithReferences> allRefs = new List<AnimesWithReferences>();
        //        allRefs.AddRange(Sequel);
        //        allRefs.AddRange(SideStory);
        //        allRefs.AddRange(SpinOff);
        //        allRefs.Add(this);

        //        if (allRefs.Count == 0)
        //            return false;
        //        else if (allRefs.Count(x => x.Aid == sr.Aid) > 0)
        //            return true;
        //        else
        //        {
        //            foreach (AnimesWithReferences s in allRefs)
        //            {
        //                if (s.ContainsItem(sr))
        //                {
        //                    Debugger.Break();
        //                }
        //            }
        //        }

        //        return false;
        //    }

        internal void Save()
        {
            new DataSaver().SaveSequels(this);
        }
    }
}